package cn.factorybox.item.aop;

import cn.factorybox.entity.UserInfo;
import cn.factorybox.item.annotation.ControllerLogAnnotation;
import cn.factorybox.item.config.JwtProperties;
import cn.factorybox.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;


/**
 * @author flypig
 * @version 1.0
 * @date 2020-11-16 3:51
 */

@Aspect
@Component
public class ControllerLogAspect {

    @Autowired
    private JwtProperties jwtProperties;

    private static final Logger log = LoggerFactory.getLogger(ControllerLogAspect.class);

    private static ThreadLocal<Map<String, Object>> threadLocal = new ThreadLocal<Map<String, Object>>();

    @Pointcut("@annotation(cn.factorybox.item.annotation.ControllerLogAnnotation)")
    public void controllerLog() {
    }

    @Before("controllerLog()")
    public void doBefore(JoinPoint joinPoint) {
        // 使用 threadLocal 保存运行方法前的时间
        long startTime = System.currentTimeMillis();
        Map<String, Object> threadInfo = new HashMap<>();
        threadInfo.put("startTime", startTime);
        // 当前执行方法名
        String method = joinPoint.getSignature().getName();
        threadInfo.put("method", method);
        // 请求参数
//        StringBuilder requestStr = new StringBuilder();
//        Object[] args = joinPoint.getArgs();
//        if (args != null && args.length > 0) {
//            for (Object arg : args) {
//                requestStr.append(arg.toString());
//            }
//        }
//        threadInfo.put("requestParams", requestStr.toString());
        threadLocal.set(threadInfo);
    }

    @AfterReturning(value = "@annotation(controllerLogAnnotation)")
    public void doAfterReturning(ControllerLogAnnotation controllerLogAnnotation) throws Exception {
        Map<String, Object> threadInfo = threadLocal.get();
        long takeTime = System.currentTimeMillis() - (long) threadInfo.getOrDefault("startTime", System.currentTimeMillis());
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        HttpServletRequest request = sra.getRequest();
        String token = request.getHeader("token");
        UserInfo userInfo = new UserInfo();
        if (token != null) {
            userInfo = JwtUtils.getInfoFromToken(token, this.jwtProperties.getKey());
        }
        log.info("{}方法结束调用  请求方式：{}  耗时={}ms  当前操作用户：{}  {}：{}", threadInfo.get("method"), request.getMethod(), takeTime, userInfo.getUsername(), controllerLogAnnotation.moduleName(), controllerLogAnnotation.functionName());
        threadLocal.remove();
    }

    @AfterThrowing(value = "@annotation(controllerLogAnnotation)", throwing = "throwable")
    public void doAfterThrowing(ControllerLogAnnotation controllerLogAnnotation, Throwable throwable) {
        log.error("{}下{}方法调用异常，异常信息：{}", controllerLogAnnotation.moduleName(), controllerLogAnnotation.functionName(), throwable.getMessage());
    }


}
